
#include "IIC.h"
#include "OLED.h"
#include "oledfont.h"
#include <string.h>

// 64*128 OLED screen
static byte screen_data[8][128] = {0};

static void OLED_send_data(byte data[], int len) {
    byte d[128 * 2 + 1] = {0};

    // slave address
    byte address = 0x78;

    // control byte : D/C# = 1 => data
    byte data_ctrl = 0x40;

    d[0] = address;
    d[1] = data_ctrl;

    memcpy(d + 2, data, len);

    IIC_output_data(d, len + 2);
}

static void OLED_send_CMD(byte cmd[], int len) {
    byte c[101] = {0};

    // slave address
    byte address = 0x78;

    // control byte : D/C# = 0 => control
    byte cmd_ctrl = 0;

    c[0] = address;
    c[1] = cmd_ctrl;

    memcpy(c + 2, cmd, len);

    IIC_output_data(c, len + 2);
}

void OLED_show_screen() {

    byte cmd[8] = {0};

    // 64 rows 8 pages
    for (int i = 0; i < 8; i++) {
        // set start page
        cmd[0] = 0xB0 + i;
        // set start column 0
        cmd[1] = 0;
        cmd[2] = 0x10;
        OLED_send_CMD(cmd, 3);
        // 128 columns
        for (int j = 0; j < 128; j++) {
            OLED_send_data(&screen_data[i][j], 1);
        }
    }
}
void OLED_set_all_bytes(byte color) {
    // 64 rows 8 pages
    for (int i = 0; i < 8; i++) {
        // 128 columns
        for (int j = 0; j < 128; j++) {
            screen_data[i][j] = color;
        }
    }
    OLED_show_screen();
}
// 局部更新 字节级
static void OLED_draw_page_column_byte(int page, int col) {
    byte cmd[3] = {0};
    // set start page
    cmd[0] = 0xB0 + page;
    // set start column 0
    cmd[1] = 0xF & col;
    cmd[2] = 0x10 + (col >> 4);
    OLED_send_CMD(cmd, 3);
    OLED_send_data(&screen_data[page][col], 1);
}

// x max 64, y  max 128
void OLED_set_pixel(int x, int y, byte color) {

    int page = x / 8;
    int bit_pos = x % 8;
    if (color > 0) {
        screen_data[page][y] |= 1 << bit_pos;
    } else {
        screen_data[page][y] &= ~(1 << bit_pos);
    }

    OLED_draw_page_column_byte(page, y);
}

void OLED_init() {

    // p();
    // open port
    IIC_init();

    byte cmd[8] = {0};

    // close display
    cmd[0] = 0xAE;
    OLED_send_CMD(cmd, 1);

    // Charge enable
    cmd[0] = 0x8D;
    cmd[1] = 0x94;
    OLED_send_CMD(cmd, 2);

    // open display
    cmd[0] = 0xAF;
    OLED_send_CMD(cmd, 1);
}

void OLED_clear() {

    byte col_color_byte = 0;
    byte cmd[8] = {0};
    // 8 pages
    for (int page = 0; page < 8; page++) {
        // set start page
        cmd[0] = 0xB0 + page;
        OLED_send_CMD(cmd, 1);

        // 128 colums per page
        for (int col = 0; col < 128; col++) {
            // set start column
            cmd[0] = col & 0xF;
            cmd[1] = 0x10 + (col >> 4);
            OLED_send_CMD(cmd, 2);
            // set color this column
            OLED_send_data(&col_color_byte, 1);
        }
    }
}

void OLED_white_screen() {

    byte col_color_byte = 0xFF;
    byte cmd[8] = {0};
    // 8 pages
    for (int page = 0; page < 8; page++) {
        // set start page
        cmd[0] = 0xB0 + page;
        OLED_send_CMD(cmd, 1);

        // 128 colums per page
        for (int col = 0; col < 128; col++) {
            // set start column
            cmd[0] = col & 0xF;
            cmd[1] = 0x10 + (col >> 4);
            OLED_send_CMD(cmd, 2);
            // set color this column
            OLED_send_data(&col_color_byte, 1);
        }
    }
}

void OLED_draw_string(int start_page, int start_column, char str[], int len) {

    byte col_color_byte = 0;
    int char_width = 6;
    int delta = 32;
    byte cmd[8] = {0};
    // set start page
    cmd[0] = 0xB0 + start_page;
    OLED_send_CMD(cmd, 1);

    // set start column
    cmd[0] = start_column & 0xF;
    cmd[1] = 0x10 + (start_column >> 4);
    OLED_send_CMD(cmd, 2);

    // column 128 bit
    // rows 8 bit per page
    // pages 8
    // display 64*128
    for (int char_index = 0; char_index < len; char_index++) {
        char c = str[char_index];

        for (int i = 0; i < char_width; i++) {
            // 每次数据写入后，GDDRAM列地址指针将自动增加一个。
            // 不用每次设置起始列
            col_color_byte = F6x8[c - delta][i];
            OLED_send_data(&col_color_byte, 1);
        }
    }
}

void OLED_draw_hanzi(int x, int y, int str[] /*存储是汉字编码*/, int len) {
    byte col_color_byte = 0;
    int char_width = 16;
    byte cmd[8] = {0};

    int row_idx = x * 2;
    for (int i = 0; i < len; i++) {
        // adjust col position
        int col_idx = y + i * char_width;
        // 上半部
        // set start page
        // rows
        cmd[0] = 0xB0 + row_idx;
        // set start column
        // colums
        cmd[1] = col_idx & 0xF;
        cmd[2] = 0x10 + (col_idx >> 4);
        OLED_send_CMD(cmd, 3);
        int shape_code_idx = str[i] * 2;
        // 每次数据写入后 , 列地址指针自动 +1
        for (int j = 0; j < char_width; j++) {
            col_color_byte = Hzk[shape_code_idx][j];
            OLED_send_data(&col_color_byte, 1);
        }

        // 下半部
        //  set start page
        // rows
        cmd[0] = 0xB0 + row_idx + 1;
        // set start column
        // colums
        cmd[1] = col_idx & 0xF;
        cmd[2] = 0x10 + (col_idx >> 4);
        OLED_send_CMD(cmd, 3);

        // 每次数据写入后 , 列地址指针自动 +1
        for (int j = 0; j < char_width; j++) {
            col_color_byte = Hzk[shape_code_idx + 1][j];
            OLED_send_data(&col_color_byte, 1);
        }
    }
}
